﻿<cfsilent>
	<cfscript>
		
		jsonAdvice = getProperty("serviceFactory").getBean("jsonAdvice");
		mathAdvice = getProperty("serviceFactory").getBean("senateMathAdvice");
		sequenceClassroomTimeTable = getProperty("serviceFactory").getBean("sequenceClassroomTimeTable");
		sequenceStudentExam = getProperty("serviceFactory").getBean("sequenceStudentExam");
		
		response = structNew();
		structInsert(response, "success", false, true);

		progress = [];
		rooms = [];
		
		examId = event.getArg("EXID");
		roomIds = event.getArg("RoomIDs");
		
		transaction {
			
			/* 加载考试任务 */
			sql = "SELECT 
						t_examtask.task_prog, 
						t_examtask.term_id, 
						t_examtask.exidx, 
						t_examtask.cid,  
						t_course.course_name,
						t_examtask.wid, 
						t_examtask.wdidx,
						t_examtask.cellidx, 
						t_examtask.campus_id 
					FROM 
						t_examtask 
						INNER JOIN t_course ON t_course.cid = t_examtask.cid 
					WHERE 
						t_examtask.task_exid = :taskExid ";
						
			queryObj = new query( datasource=application.dnsMaster );
			queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
			
			rs_examTask = queryObj.execute( sql=sql ).getResult();
			
			arrayAppend( progress, "检查考试安排状态" );

			if ( rs_examTask.task_prog eq "1" ) {
				
				termId = rs_examTask.term_id;
				examIdx = rs_examTask.exidx;
				courseId = rs_examTask.cid;
				courseName = rs_examTask.course_name;

				/* 获取考试的教学班列表 */
				sql = "SELECT task_id FROM t_examplan 
						WHERE cid = :courseId 
							  AND 
							  term_id = :termId 
							  AND 
							  exidx = :examIndex "; 
				
				queryObj = new query( datasource=application.dnsMaster ); 
				queryObj.addParam( name="courseId", value=courseId, cfsqltype="cf_sql_varchar" );
				queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
				queryObj.addParam( name="examIndex", value=examIdx, cfsqltype="cf_sql_char" );
				rs_taskIds= queryObj.execute( sql=sql ).getResult(); 
	
	
				/* 选课且已缴费的学生 */
				sql = "SELECT 
							stu_id, scc_id 
						FROM  
							t_student_course 
						WHERE 
							task_id IN (:taskIds) 
							AND 
							SUBSTR(choose_prop, 2, 1) = '1' 
						ORDER BY 
							task_id"; 
				
				queryObj = new query( datasource=application.dnsMaster ); 
				queryObj.addParam( name="taskIds", value=arrayToList(rs_taskIds["task_id"],"|"), cfsqltype="cf_sql_varchar", list=true, separator="|" );
				rs_student = queryObj.execute( sql=sql ).getResult(); 
				

				/* 随机编排学生 进行1/3乱序交换 */
				/*
				for ( i=1; i lt arrayLen(studentArray); i=i+3 ) {
					
					p1 = randRange(1, int(arrayLen(studentArray)/2-1), "SHA1PRNG");
					p2 = randRange(int(arrayLen(studentArray)/2), arrayLen(studentArray), "SHA1PRNG");
					
					arraySwap(studentArray, p1, p2);
				}
				*/

				studentCount = rs_student.recordCount;

				arrayAppend( progress, "刷新参考人数为 " & studentCount & "人" );
				
									
				examWeek = int(rs_examTask.wid);
				examWeekDay = rs_examTask.wdidx;
				examCell = rs_examTask.cellidx;
				campusId = rs_examTask.campus_id;	
				
				examWeekIdx = mathAdvice.convertExamWeekIdx(examWeek);
				
				cells = 2;
				/* 如果为 第二讲 或 第五讲 则使用最长学时数 */
				if (examCell eq 2 or examCell eq 5) { cells = 3; }
				
				cellStart = mathAdvice.convertLectureIdxToCellStart(examCell);
				cellEnd = cellStart + cells -1;
				
				/* 根据已选教室 教学楼和楼层进行排序 */
				
				sql = "SELECT 
							a.cr_id, 
							a.classroom, 
							a.sits_exam 
						FROM 
							t_classroom a 
						WHERE 
							a.cr_id IN (:roomIds) 
							AND 
							a.campus_id = :campusId 
							AND 
							NOT EXISTS(
								SELECT 1 FROM t_clsroom_timetable b 
								WHERE 
								  b.cr_id = a.cr_id 
								  AND 
								  b.term_id = :termId 
								  AND 
								  b.wdidx = :weekDay 
								  AND 
								  NOT (b.cellidx + b.cellrelay - 1 < :cellStart OR b.cellidx > :cellEnd) 
								  AND 
								  SUBSTR(b.widx, #int(examWeek)#, 1) = '1' ) 
						ORDER BY 
							 a.b_id, a.cr_floor, a.classroom ";
				
				queryObj = new query( datasource=application.dnsMaster ); 
				queryObj.addParam( name="roomIds", value=roomIds, cfsqltype="cf_sql_char", list=true, separator="|" );
				queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
				queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
				queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_integer" );
				queryObj.addParam( name="cellEnd", value=cellEnd, cfsqltype="cf_sql_integer" );
				queryObj.addParam( name="campusId", value=campusId, cfsqltype="cf_sql_char" );
				
				rs_clsroom = queryObj.execute( sql=sql ).getResult();
					
				sitsCount = 0;
						
				for ( i=1; i LTE rs_clsroom.recordCount; i++){
					sitsCount = sitsCount + rs_clsroom["sits_exam"][i];
				}
				
				arrayAppend( progress, "已选教室" & rs_clsroom.recordCount & "个, 考场最高容量" & sitsCount & "座" );
				
				if ( sitsCount gte studentCount ) {
					
					/* 教室足够 */
					/* 开始平均分布考场和人数 */
					
					clsroomToArrange = [];
					sitsUsed = 0;
					
					for ( i=1; i LTE rs_clsroom.recordCount; i++){
								
						sitsUsed = sitsUsed + rs_clsroom["sits_exam"][i];
								
						arrayAppend(clsroomToArrange, [ rs_clsroom["cr_id"][i], rs_clsroom["classroom"][i], rs_clsroom["sits_exam"][i], 0 ] );
						
						if ( sitsUsed gte studentCount ) {
							break;
						}
					}
					
					roomCount = arrayLen(clsroomToArrange);
							
					/* 平均分配学生座次 */
					studentAvgPerRoom = int( studentCount / roomCount );
					studentLeft = studentCount;
							
					/* 先按照平均数分配人数 */
					for ( i=1; i lte roomCount; i++ ) {
								
						if ( clsroomToArrange[i][3] gte studentAvgPerRoom ) {
							clsroomToArrange[i][4] = studentAvgPerRoom;
							studentLeft = studentLeft - studentAvgPerRoom;
						}
						else {
							clsroomToArrange[i][4] = clsroomToArrange[i][3];
							studentLeft = studentLeft - clsroomToArrange[i][3];
						}
								
					}
														
					/* 再平均分配剩余人数 */
					while ( studentLeft gt 0 ) {

						for ( i=1; i lte roomCount; i++ ) {

							if ( studentLeft eq 0) {
								break;
							}
									
							if ( clsroomToArrange[i][4] lt clsroomToArrange[i][3] ) {
								clsroomToArrange[i][4] ++;
								studentLeft --;
							}

						}

					}
					
					arrayAppend( progress, "平均分布考场学生到" & roomCount & "个考场" );
					
					studentStart = 0;
					studentEnd = 0;
					
					for ( clsroomTarget in clsroomToArrange ) {
								
						/* 标注该考场已用于考试 */
						sql = "SELECT classroom, sits_exam FROM t_classroom WHERE cr_id = :classroomId"; 
						
						queryObj = new query( datasource=application.dnsMaster );
						queryObj.addParam( name="classroomId", value=clsroomTarget[1], cfsqltype="cf_sql_char" );
						
						rs_classRoom = queryObj.execute( sql=sql ).getResult();
						
						sequenceClassroomTimeTable.setTermID(termId);
						sequenceClassroomTimeTable.setClassroomID(clsroomTarget[1]);
						useIdx = sequenceClassroomTimeTable.getIDX();
						
						sequenceClassroomTimeTable.setIndex(useIdx);
						useId = sequenceClassroomTimeTable.getID();
						
						sql = "INSERT INTO t_clsroom_timetable 
										(
											 crtime_id,
											 uidx,
											 widx,
											 wdidx,
											 cellidx,
											 cellrelay,
											 term_id,
											 cr_id,
											 ut_id
										)VALUES(
											 :classRoomTimeID ,
											 :useIndex ,
											 :weekIndex ,
											 :weekDay ,
											 :cellStart ,
											 :cellLength ,
											 :termId ,
											 :classRoom ,
											 :usage 
										)";
						
						queryObj = new Query( datasource=application.dnsMaster );
						queryObj.addParam( name="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char" );
						queryObj.addParam( name="weekIndex", value=mathAdvice.convertExamWeekIdx(examWeek), cfsqltype="cf_sql_char" );
						queryObj.addParam( name="weekDay", value=examWeekDay, cfsqltype="cf_sql_char" );
						queryObj.addParam( name="cellStart", value=cellStart, cfsqltype="cf_sql_interger" );
						queryObj.addParam( name="cellLength", value=cells, cfsqltype="cf_sql_interger" );
						queryObj.addParam( name="useIndex", value=useIdx, cfsqltype="cf_sql_char" );
						queryObj.addParam( name="termId", value=termId, cfsqltype="cf_sql_char" );
						queryObj.addParam( name="classRoom", value=clsroomTarget[1], cfsqltype="cf_sql_char" );
						queryObj.addParam( name="usage", value="3", cfsqltype="cf_sql_char" );
						queryObj.execute( sql=sql );
						
						sql = "INSERT INTO t_clsroom_forexam 
									(
										 crtime_id,
										 task_exid,
										 exam_course 
									)VALUES(
										 :ClassRoomTimeID ,
										 :taskExamID ,
										 :examCourse 
									)";
								
						queryObj = new Query(datasource = application.dnsMaster);
						queryObj.addParam(name ="ClassRoomTimeID", value=useId, cfsqltype="cf_sql_char");
						queryObj.addParam(name ="taskExamID", value=examId, cfsqltype="cf_sql_varchar");
						queryObj.addParam(name ="examCourse", value=courseName, cfsqltype="cf_sql_varchar");
						queryObj.execute(sql = sql);
												
								
						/* 依次编排学生座位及考场 */
						sitidx = 0;
								
						studentStart = studentEnd + 1;
						studentEnd = studentEnd + clsroomTarget[4];
								
						for ( i=studentStart; i lte studentEnd; i++ ) {
									
							sitidx++;
							
							sequenceStudentExam.setTaskExamID(examId);
							sequenceStudentExam.setStudentID(rs_student["stu_id"][i]);
							
							stuExamId = sequenceStudentExam.getID();
							
							sql = "INSERT INTO t_student_exam(
												scex_id, 
												task_exid, 
												stu_id, 
												cr_id, 
												sitidx, 
												scc_id 
											)VALUES(
												:examerID, 
												:taskExid, 
												:studentId, 
												:classroomId, 
												:sitIndex, 
												:chooseId 
											)";
							
							queryObj = new query( datasource=application.dnsMaster );
							queryObj.addParam( name="examerID", value=stuExamId, cfsqltype="cf_sql_varchar" ); 
							queryObj.addParam( name="taskExid", value=examId, cfsqltype="cf_sql_char" );
							queryObj.addParam( name="studentId", value=rs_student["stu_id"][i], cfsqltype="cf_sql_varchar" );
							queryObj.addParam( name="classroomId", value=clsroomTarget[1], cfsqltype="cf_sql_char" );
							queryObj.addParam( name="sitIndex", value=sitidx, cfsqltype="cf_sql_integer" );
							queryObj.addParam( name="chooseId", value=rs_student["scc_id"][i], cfsqltype="cf_sql_varchar" );
							
							queryObj.execute( sql=sql );
						
						}
								
						arrayAppend( rooms, [rs_classRoom.classroom, rs_classRoom.sits_exam, clsroomTarget[4], studentStart, studentEnd ] );
								
					}
					/* 刷新考试人数 */							
					/* 更新考试状态为已安排场地 */
					
					sql = "UPDATE t_examtask SET examer_sum = :examSize, task_prog = :taskProg WHERE task_exid = :taskExamId ";
					 
					queryObj = new query( datasource=application.dnsMaster ); 
					queryObj.addParam( name="examSize", value=studentCount, cfsqltype="cf_sql_integer" ); 
					queryObj.addParam( name="taskProg", value="2", cfsqltype="cf_sql_char" ); 
					queryObj.addParam( name="taskExamId", value=examId, cfsqltype="cf_sql_char" ); 
					
					queryObj.execute( sql=sql );
												
					arrayAppend( progress, "编排学生座次完成" );
							
					structInsert(response, "success", true, true);
					
					
				}
				else {
					/* 考场不足 */
					structInsert(response, "reason", "当前考试时间没有足够的考场", true);
				}
				
			}
			else {
				structInsert(response, "ExamID", examId, true);
				structInsert(response, "reason", "考试状态异常 标注为等待安排场地状态", true);
				
			}
			
		}
		
		structInsert(response, "Progress", progress, true);
		structInsert(response, "ClassRoom", rooms, true);
		
	</cfscript>
</cfsilent><cfoutput>#jsonAdvice.encode(data:response, stringNumbers:true)#</cfoutput>